#ifndef THREAD_POOL_HPP
#define THREAD_POOL_HPP

#include <iostream>
#include <queue>
#include <pthread.h>
#include "Task.hpp"
#include "Log.hpp"

#define THREAD_NUM 10

class ThreadPool
{
private:
    std::queue<Task> task_queue;
    pthread_mutex_t lock;
    pthread_cond_t cond;
    int thread_num;
    bool stop;
    static ThreadPool* instance;

public:
    ThreadPool(int _thread_num = THREAD_NUM): thread_num(_thread_num), stop(false)
    {}
    const ThreadPool& operator=(const ThreadPool&) = delete;
    ThreadPool(const ThreadPool&) = delete;

public:
    static ThreadPool* GetInstance()
    {
        static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
        if(instance == nullptr)
        {
            pthread_mutex_lock(&mutex);
            if(instance == nullptr)
            {
                instance = new ThreadPool();
                instance->InitThreadPool();
            }
            pthread_mutex_unlock(&mutex);
        }
        return instance;
    }

    bool IsStop()
    {
        return stop;
    }

    bool TaskQueueIsEmpty()
    {
        return task_queue.empty();
    }

    void Lock()
    {
        pthread_mutex_lock(&lock);
    }

    void UnLock()
    {
        pthread_mutex_unlock(&lock);
    }

    void ThreadWait()
    {
        pthread_cond_wait(&cond, &lock);
    }

    void ThreadWakeUp()
    {
        pthread_cond_signal(&cond);
    }

    static void* ThreadRoutine(void* arg)
    {
        ThreadPool* tp = (ThreadPool*)arg;
        while(true)
        {
            Task task;
            tp->Lock();
            while(tp->TaskQueueIsEmpty())   
            {
                tp->ThreadWait();   // 当我醒来的时候，一定是占有互斥锁的！
            }
            tp->PopTask(task);
            tp->UnLock();
            task.ProcessOn();
        }  
    }

    bool InitThreadPool()
    {
        for(int i = 0; i < thread_num; i++)
        {
            pthread_t tid;
            if(pthread_create(&tid, nullptr, ThreadRoutine, this))
            {
                LOG(FATAL, "Create thread failed!");
                return false;
            }
        }
        LOG(INFO, "Create thread success...");
        return true;
    }

    void PushTask(const Task& task)
    {
        Lock();
        task_queue.push(task);
        UnLock();
        ThreadWakeUp();
    }   

    void PopTask(Task& task)
    {
        task = task_queue.front();
        task_queue.pop();
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }
};
ThreadPool* ThreadPool::instance = nullptr;

#endif